home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Merciful 1
/
Merciful - Disc 1.iso
/
software
/
f
/
friday_night_pool
/
fridaynightpool.dms
/
fridaynightpool.adf
/
source
/
comp.c
next >
Wrap
C/C++ Source or Header
|
1978-02-25
|
13KB
|
507 lines
#include <exec/types.h>
#define CUE 0
#define BLK 5
#define BASE 200 /* V.important constant. Used in ALL physical calcs. */
#define BASESP 1000
#define BASEII 4 /* For root calcs which need plenty of precision */
#define TABLELENGTH (272 * BASE) /* 272 is actual length in pixels */
#define TABLEWIDTH ((TABLELENGTH * 5 / 8)-BASE)
#define X1CORNER 24
#define Y1CORNER 62
#define X2CORNER (X1CORNER + TABLELENGTH / BASE)
#define Y2CORNER (Y1CORNER + TABLEWIDTH / BASE)
#define BALLRADIUS (7 * BASE) /* 7 pixels */
#define BALLDIAMETER (BALLRADIUS * 2)
#define SCRNBALLDIAMETER (BALLDIAMETER / BASE)
#define SEMICIRCRAD (TABLEWIDTH/6)
#define PLACEPACK (TABLELENGTH * 5 / 8)
#define PACKHORIZSEP (BALLDIAMETER - 2*BASE)
#define POCKET (BALLRADIUS + 5*BASE)
#define NEARPOCKET (9*BASE)
#define SCRNPOCKET (POCKET / BASE)
#define CUETIP 10
#define MAXCUELENGTH 80
#define CLOCKWISE 1
#define ANTICLOCKWISE 2
#define SMALL 1
#define LARGE 2
#define UP 1
#define DOWN 2
#define NOHIT -1
#define ON TRUE
#define OFF FALSE
#define HIT 3
#define UPDATE 3
#define ICON 2
#define FRICTION (BASESP / 500)
#define SPINFRICTION 3
#define SPEEDINC (BASESP / 16)
#define MAXSPEED (BASESP * 4)
#define DEFAULT 30000
#define RACKED 1
#define BROKEN 0
#define OPEN 2
#define PRACTICE 2
#define CLEARJAWS 0
#define BALLINJAWS 1
#define AVOIDJAWS 2
void ChangePower();
void ChangeSpin(void);
void DrawCross(short);
void MoveCue(short,short);
short FindAngle(WORD,WORD,WORD);
short TouchingBall(short);
void PlayComputerShot(void);
void CopyBalls(struct ballstruct *,struct ballstruct *);
WORD QuickRoot(long);
void CheckAngle(short *);
short NearPocket(short);
short CheckPocket(short);
UWORD Rand(UWORD);
enum msg { MSG_PLACECUEBALL,MSG_FOUL,MSG_WINS,MSG_MICHAEL,MSG_JOSH,
MSG_CLAIRE,MSG_SALLY,MSG_PLAYER1,MSG_PLAYER2,MSG_QUITTING,
MSG_VS,MSG_GAME,MSG_OF,MSG_0,MSG_1,MSG_2,MSG_3,MSG_4,MSG_5,
MSG_GOODSHOT,MSG_SHOTCANCELLED,MSG_BADLUCK,MSG_WELLDONE,
MSG_QUITGAME,MSG_ISTHECHAMP,MSG_OOOPS };
enum balltype { white,black,yellow,red, anyball,baize };
struct ballstruct
{
enum balltype colour;
char potted,justpotted,hasmoved,lasthit,olddx,olddy;
USHORT x,y;
short speed,angle,scrnx,scrny,oldscrnx,oldscrny;
};
struct ballstruct ball[16],tempball[16];
struct playerstruct
{
enum balltype colour;
char goes,wins;
char nametag;
short maxpower;
char cuepulls,skill;
};
struct playerstruct player[8];
short *memblock, *quicksin, *quickcos, *quickarcsin;
WORD cueangle,cuespeed,powerdirn,spinx,spiny;
short gametype,cloth,firsthit,packstate,turn,foul,balls,
endofgame,cheatangle,cheatball;
USHORT pocketx[6] = { (TABLELENGTH-BALLRADIUS),(TABLELENGTH-BALLRADIUS),
(TABLELENGTH/2),(TABLELENGTH/2),BALLRADIUS,BALLRADIUS };
USHORT pockety[6] = { (TABLEWIDTH-BALLRADIUS),BALLRADIUS,
(TABLEWIDTH-BALLRADIUS),BALLRADIUS,(TABLEWIDTH-BALLRADIUS),BALLRADIUS };
char angleused[360];
/**********************/
short TouchingBall(col)
short col;
{
register short i;
for (i=0; i<balls; i++)
{
if (!ball[i].potted && i!=col)
{
register long dx = ball[col].x - ball[i].x;
if (dx < BALLDIAMETER && dx > (-BALLDIAMETER))
{
register long dy = ball[col].y - ball[i].y;
if (dy < BALLDIAMETER && dy > (-BALLDIAMETER))
if (QuickRoot(dx*dx + dy*dy) < BALLDIAMETER)
return(i);
}
}
}
return(NOHIT);
}
/************************/
short NearPocket(i)
short i;
{
char j;
for (j=0; j<6; j++)
if (abs(ball[i].x - pocketx[j]) < NEARPOCKET &&
abs(ball[i].y - pockety[j]) < NEARPOCKET) return(TRUE);
return(FALSE);
}
/************************/
short CheckPocket(i)
short i;
{
short j;
for (j=1; j<balls; j++)
{
if (!ball[j].potted &&
abs(ball[j].x - pocketx[i]) < NEARPOCKET &&
abs(ball[j].y - pockety[i]) < NEARPOCKET) return(j);
}
return(FALSE);
}
/************************/
void PlayComputerShot()
{
short i,j,k,l,limit,opp,adj,dx,dy,angle,hitball,
hypcue,anglecol,hypcol,anglecue,relangle,
potspeed=DEFAULT,hitspeed=DEFAULT,speed,
potangle,hitangle,potbackspin,nearpocket,
jaws,forgetcolour=FALSE;
long x,y;
CopyBalls(ball,tempball);
/* CPU can forget its ball colour! */
if (player[turn].skill==0 && player[turn].colour!=black && !(Rand(10)))
forgetcolour=TRUE;
for(i=1; i<balls; i++)
if ((ball[i].colour==player[turn].colour ||
(forgetcolour && ball[i].colour!=black) ||
(ball[i].colour!=black && player[turn].colour==anyball) ||
gametype==PRACTICE) && !ball[i].potted)
{
for (j=0; j < (6+1); j++)
{
if (j==6)
{
opp = (ball[i].x - ball[CUE].x) / BASEII;
adj = (ball[i].y - ball[CUE].y) / BASEII;
hypcue = QuickRoot(opp*opp + adj*adj);
anglecue = FindAngle(opp,adj,hypcue);
anglecol = anglecue; hypcol = hypcue;
relangle = 0;
}
else
{
opp = (pocketx[j] - ball[i].x) / BASEII;
adj = (pockety[j] - ball[i].y) / BASEII;
hypcol = QuickRoot(opp*opp + adj*adj);
anglecol = FindAngle(opp,adj,hypcol);
x = ball[i].x - SCRNBALLDIAMETER * quicksin[anglecol];
y = ball[i].y - SCRNBALLDIAMETER * quickcos[anglecol];
opp = (x - ball[CUE].x) / BASEII;
adj = (y - ball[CUE].y) / BASEII;
hypcue = QuickRoot(opp*opp + adj*adj);
anglecue = FindAngle(opp,adj,hypcue);
relangle = abs(anglecol-anglecue);
if (relangle > 180) relangle=360-relangle;
}
if (relangle < 70)
{
dx = quicksin[anglecue]<<1;
dy = quickcos[anglecue]<<1;
limit = hypcue / ((BASE<<1)/BASEII) + 10;
for (k=0; k<limit; k++)
{
hitball=TouchingBall(CUE);
if (hitball!=NOHIT) break;
ball[CUE].x+=dx; ball[CUE].y+=dy;
}
nearpocket = NearPocket(CUE);
ball[CUE].x = tempball[CUE].x;
ball[CUE].y = tempball[CUE].y;
if (hitball!=NOHIT && hitball!=i && !nearpocket &&
(ball[hitball].colour==player[turn].colour ||
(player[turn].colour==anyball &&
ball[hitball].colour!=black)))
{
speed = hypcue * (BASEII*MAXSPEED/BASE) / 600;
if (speed < hitspeed)
{ hitspeed = speed; hitangle = anglecue; }
}
else if (hitball==i && !nearpocket)
{
/* Cue ball path is clear */
dx = quicksin[anglecol] << 1;
dy = quickcos[anglecol] << 1;
do
{
ball[i].x += dx; ball[i].y += dy;
hitball = TouchingBall(i);
if (ball[i].x < BALLRADIUS ||
ball[i].x > (TABLELENGTH-BALLRADIUS) ||
ball[i].y < BALLRADIUS ||
ball[i].y > (TABLEWIDTH-BALLRADIUS)) break;
} while (hitball==NOHIT);
ball[i].x = tempball[i].x;
ball[i].y = tempball[i].y;
if (hitball==NOHIT && j!=6) /* We've found a pot! */
{
speed = (hypcol+hypcue) * (BASEII*MAXSPEED/BASE)
/ ((100-relangle)*4)
* (hypcol+(TABLELENGTH/BASEII))
/ (hypcue+(TABLELENGTH/BASEII));
if (speed < potspeed)
{
potspeed = speed; potangle = anglecue;
/* check for in/off situ */
if (relangle < 5 || NearPocket(i))
potbackspin = TRUE;
else potbackspin = FALSE;
if (player[turn].nametag==MSG_JOSH ||
player[turn].nametag==MSG_PLAYER1 ||
player[turn].nametag==MSG_PLAYER2)
{ cheatangle = anglecol; cheatball = i; }
}
}
else if (potspeed==DEFAULT)
{
/* Can hit but not pot */
if (hitball!=NOHIT && NearPocket(hitball))
{
if (ball[hitball].colour==
player[turn].colour ||
(player[turn].colour==anyball &&
ball[hitball].colour!=black))
jaws = BALLINJAWS;
else jaws = AVOIDJAWS;
}
else jaws = CLEARJAWS;
speed = hypcue * (BASEII*MAXSPEED/BASE)
/ ((100-relangle)*3);
if (jaws==BALLINJAWS) speed<<=2;
if (speed < hitspeed && jaws!=AVOIDJAWS)
{
hitspeed = speed;
hitangle = anglecue;
}
}
}
}
}
}
if (hitspeed==DEFAULT && potspeed==DEFAULT) /* Snooker situation */
{
for(i=1; i<balls; i++)
if ((ball[i].colour==player[turn].colour ||
(ball[i].colour!=black && player[turn].colour==anyball) ||
gametype==PRACTICE) && !ball[i].potted)
{
for (j=0; j<4; j++) for (l=0; l<5; l++)
{
short xdisp,ydisp;
long dx,dy;
switch(l)
{
case 0: xdisp = 0; ydisp = 0; break;
case 1: xdisp = (-BALLRADIUS);
ydisp = (-BALLRADIUS); break;
case 2: xdisp = BALLRADIUS;
ydisp = (-BALLRADIUS); break;
case 3: xdisp = (-BALLRADIUS);
ydisp = BALLRADIUS; break;
case 4: xdisp = BALLRADIUS;
ydisp = BALLRADIUS; break;
}
dx = ball[i].x+xdisp - ball[CUE].x;
dy = ball[i].y+ydisp - ball[CUE].y;
switch(j)
{
case 0: y = ball[CUE].y +
dy * ball[CUE].x /
(ball[i].x+xdisp + ball[CUE].x);
x = BALLRADIUS; break;
case 1: y = ball[CUE].y +
dy * (TABLELENGTH - ball[CUE].x) /
((TABLELENGTH - (ball[i].x+xdisp)) +
(TABLELENGTH - ball[CUE].x));
x = TABLELENGTH - BALLRADIUS; break;
case 2: x = ball[CUE].x +
dx * ball[CUE].y /
(ball[i].y+ydisp + ball[CUE].y);
y = BALLRADIUS; break;
case 3: x = ball[CUE].x +
dx * (TABLEWIDTH - ball[CUE].y) /
((TABLEWIDTH - (ball[i].y+ydisp)) +
(TABLEWIDTH - ball[CUE].y));
y = TABLEWIDTH - BALLRADIUS; break;
}
opp = (x - ball[CUE].x) / BASEII;
adj = (y - ball[CUE].y) / BASEII;
hypcue = QuickRoot(opp*opp + adj*adj);
anglecue = FindAngle(opp,adj,hypcue);
opp = (x - (ball[i].x+xdisp)) / BASEII;
adj = (y - (ball[i].y+ydisp)) / BASEII;
hypcol = QuickRoot(opp*opp + adj*adj);
dx = quicksin[anglecue] << 1;
dy = quickcos[anglecue] << 1;
do
{
ball[CUE].x += dx; ball[CUE].y += dy;
if (ball[CUE].x < BALLRADIUS ||
ball[CUE].x > (TABLELENGTH-BALLRADIUS) ||
ball[CUE].y < BALLRADIUS ||
ball[CUE].y > (TABLEWIDTH-BALLRADIUS)) break;
hitball = TouchingBall(CUE);
} while (hitball==NOHIT);
if (hitball==NOHIT && !(NearPocket(CUE)))
{
/* Path to cushion is clear */
if (j <= 1) dx = -dx; else dy = -dy;
limit = (hypcol / ((BASE<<1)/BASEII)) + 10;
for (k=0; k<limit; k++)
{
hitball=TouchingBall(CUE);
if (hitball!=NOHIT) break;
ball[CUE].x += dx; ball[CUE].y += dy;
}
if (hitball==i)
{
/* Found a path off a cushion! */
speed = (hypcue+hypcol) *
(BASEII*MAXSPEED/BASE) / 300;
if (speed < hitspeed)
{
hitspeed = speed;
hitangle = anglecue;
ball[CUE].x = tempball[CUE].x;
ball[CUE].y = tempball[CUE].y;
break;
}
}
}
ball[CUE].x = tempball[CUE].x;
ball[CUE].y = tempball[CUE].y;
}
}
}
spiny = (Rand(1200)+Rand(1200))/2 - 800;
if (potspeed != DEFAULT)
{
ball[CUE].speed = potspeed + Rand((UWORD)(potspeed>>1));
ball[CUE].angle = potangle;
if (potbackspin) /* could be an "in/off" situ */
spiny = (Rand(800)+Rand(800))/2 - 800;
}
else if (hitspeed != DEFAULT)
{
ball[CUE].speed = hitspeed + Rand(MAXSPEED);
ball[CUE].angle = hitangle;
}
else /* Ooops! We're fully snookered! */
{
short lasthope=FALSE;
/* Try to illegally knock in any of our balls over pockets */
for (i=0; i<6; i++)
{
if ((j = CheckPocket(i)) &&
ball[j].colour==player[turn].colour &&
(player[turn].colour!=black ||
(player[turn].colour==anyball &&
ball[j].colour!=black)))
{
opp = (pocketx[i] - ball[CUE].x) / BASEII;
adj = (pockety[i] - ball[CUE].y) / BASEII;
hypcue = QuickRoot(opp*opp + adj*adj);
ball[CUE].angle = FindAngle(opp,adj,hypcue);
ball[CUE].speed = player[turn].maxpower;
spiny = (Rand(800)+Rand(800))/2 - 800;
lasthope = TRUE; break;
}
}
if (!lasthope)
{
ball[CUE].angle = Rand(360);
ball[CUE].speed = player[turn].maxpower;
/* little anim! */
j = 36 + Rand(49);
for (i=0; i<j; i++) MoveCue(CLOCKWISE,LARGE);
}
}
if (packstate==RACKED) ball[CUE].speed = player[turn].maxpower;
/* Add player characteristics */
angle = ((Rand(8)-4) * (3-player[turn].skill))/3;
if (player[turn].colour==black) angle*=2;
ball[CUE].angle+=angle;
CheckAngle(&ball[CUE].angle);
ball[CUE].speed = ball[CUE].speed * player[turn].maxpower / MAXSPEED;
if (ball[CUE].speed > player[turn].maxpower)
ball[CUE].speed = player[turn].maxpower;
if (ball[CUE].speed < BASESP) ball[CUE].speed=BASESP;
if (ball[CUE].speed > MAXSPEED) ball[CUE].speed=MAXSPEED;
angle = ball[CUE].angle+180;
CheckAngle(&angle);
i=LARGE; j=0;
while(cueangle!=angle)
{
if ((angle-cueangle<180 && angle-cueangle>=0) ||
angle-cueangle<-180)
{
if (j==2) i=SMALL;
j=1; MoveCue(CLOCKWISE,i);
}
else
{
if (j==1) i=SMALL;
j=2; MoveCue(ANTICLOCKWISE,i);
}
}
while(cuespeed < ball[CUE].speed) { ChangePower(); WaitTOF(); }
PlayShot();
}